
/**
 ***********************************************************************
 * @brief 图片编辑
 * 
 ************************************************************************
 */
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#include "picture_edit.h"



/**
 * @brief 图片读取
 * 
 * 
 */
int read_buffer(void *opaque, void *buf, int buf_size){
	int size = -1;
	picture_edit_t *edit_ctx = (picture_edit_t *)opaque;
	if(!feof(edit_ctx->in_file)){
		size = fread(buf,1,buf_size,edit_ctx->in_file);
	}
	
	return size;
}
 
/**
 * @brief 图片写入
 * 
 * 
 */
int write_buffer(void *opaque, void *buf, int buf_size)
{
	picture_edit_t *edit_ctx = (picture_edit_t *)opaque;
	while((edit_ctx->length + buf_size) > edit_ctx->max)
	{
		edit_ctx->data = realloc(edit_ctx->data, edit_ctx->max << 1);
		if(NULL == edit_ctx->data)
			return -1;
		edit_ctx->max = edit_ctx->max << 1;
	}
	
	memcpy(edit_ctx->data+edit_ctx->length, buf, buf_size);
	edit_ctx->length += buf_size;	

	return buf_size;
}
 
int write_file(uint8_t *data, uint32_t length)
{
	FILE *out_file;
	out_file = fopen("test_1.png","wb+");
	if(!out_file)
	{
		printf("open %s failed \n", "test_11.png");
		return -1;
	}

	fwrite(data, 1, length, out_file);
	fclose(out_file);
	return 0;
}


int picture_edit_init(picture_edit_t *edit_ctx, char *src_path, const char *filter_descr)
{
	
    memset(edit_ctx, 0, sizeof(picture_edit_t));

	edit_ctx->in_file = fopen(src_path, "rb");
	if(!edit_ctx->in_file)
	{
		printf("open %s failed \n", src_path);
		return -1;
	}

	// edit_ctx->out_file = fopen("test_22.jpg","wb+");

	edit_ctx->data = (uint8_t *)malloc(DEFAULT_PICTURE_SIZE);
	if(NULL == edit_ctx->data)
	{
		printf("Error malloc %d failed \n", DEFAULT_PICTURE_SIZE);
		return -1;
	}
	edit_ctx->max  = DEFAULT_PICTURE_SIZE;
	edit_ctx->length = 0;    

    if(0 != picture_codec_init(&edit_ctx->ffmpeg_context, edit_ctx, read_buffer, write_buffer, filter_descr))
	{
		printf("picture_codec_init failed \n");
		return -1;
	}
	return 0;
}


void picture_edit_exit(picture_edit_t *edit_ctx)
{
    fclose(edit_ctx->in_file);
    // fclose(edit_ctx->out_file);
	free(edit_ctx->data);
    picture_codec_exit(&edit_ctx->ffmpeg_context);
}




/**
 * @brief 亮度
 * 	Luminance: 指的是投射在固定方向和面积上面的发光强度，发光强度是一个可测量的属性
 *  Brightness: 亮度是光的主观属性，显示器从暗到亮之间可以调节成不同程度等级的亮度，不能通过测量来客观评估（但可以说成比例，如50%的亮度）。
 * 
 * eq=brightness 效果和 hue=b=%f 一致
 */
uint8_t *changePictureLuminance(char *sourcePath, float luminace)
{
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   

    if(luminace > 10.0) luminace = 10.0;
	if(luminace < -10.0) luminace = -10.0;	
	// sprintf(filter_descr, "eq=brightness=%f", luminace);
	sprintf(filter_descr, "hue=b=%.1f", luminace);

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}


/**
 * @brief 对比度
 * @details
 * 		contrast 	是对比度
 * 		brightness 	是明亮 可以是小数
 * 
 */
uint8_t *changePictureConstrast(char *sourcePath, float constrast)
{
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   

    if(constrast > 9.0) constrast = 9.0;
	if(constrast < 1.0) constrast = 1.0;
	
	// 增加对比度
	if(constrast > 0)
		sprintf(filter_descr, "eq=contrast=%.1f", constrast);
	else // 模糊
		sprintf(filter_descr, "eq=contrast=%.1f", constrast);
    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}


/**
 * @brief 饱和度
 */
uint8_t *changePictureSaturation(char *sourcePath, float saturation)
{
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   

    if(saturation > 3.0) saturation = 3.0;
	if(saturation < -0) saturation = -0;	
	sprintf(filter_descr, "eq=saturation=%.1f", saturation);

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}


/**
 * @brief 色温
 * @details 条件 红蓝两色，负数调节红色，正数数添加蓝色
 * 			每种颜色的范围是 [-1.0 1.0]
 */
uint8_t *changePictureTemperature(char *sourcePath, float temperature)
{
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   
	
	if(temperature > 2.0) temperature = 2.0;
	if(temperature < -2.0) temperature = -2.0;	
	if(temperature > 0)
	{
		sprintf(filter_descr, "colorbalance=rm=%.1f:bm=%.1f", 0.0, temperature-1.0);
	}
	else
	{
		sprintf(filter_descr, "colorbalance=rm=%.1f:bm=%.1f", temperature+1.0, 0.0);
	}

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}


/**
 * @brief  亮部: 在 Pshotoshop 中就是阴影和高光
 * @details 每个值的取值范围 [-1.0 1.0]
 */
uint8_t *changePictureBrightPart(char *sourcePath, float brightScale)
{
	char filter_descr[256] = {0}; 
	picture_edit_t edit_ctx;   

    if(brightScale > 1.0) brightScale = 1.0;
	if(brightScale < -1.0) brightScale = -1.0;	
	sprintf(filter_descr, "colorbalance=rh=%.1f:gh=%.1f:bh=%.1f", brightScale, brightScale, brightScale);

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}

/**
 * @brief 暗部
 */
uint8_t *changePictureDarkPart(char *sourcePath, float darkScale)
{	
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   

    if(darkScale > 1.0) darkScale = 1.0;
	if(darkScale < -1.0) darkScale = -1.0;	
	sprintf(filter_descr, "colorbalance=rs=%.1f:gs=%.1f:bs=%.1f", darkScale, darkScale, darkScale);

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}

/**
 * @brief 黑白
 * @details 彩色转换黑白
 *		y 参数调整亮度		    [0-256]
 *		u 参数调整蓝色平衡  	[0-256]
 *		v 参数调整红色平衡 		[0-256]
 */
uint8_t *changeBlackAndWhite(char *sourcePath, float scaleValue)
{
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   

	int value = (int)scaleValue;
    if(value > 256) value = 256;
	if(value < 0) value = 0;	
	sprintf(filter_descr, "lutyuv=u=%d:v=%d", value, value);

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);

	return NULL;
}


/**
 * @brief 锐度
 */
uint8_t *changePictureSharpness(char *sourcePath, float sharpness)
{
	char filter_descr[40] = {0}; 
	picture_edit_t edit_ctx;   

    if(sharpness > 5.0) sharpness = 5.0;
	if(sharpness < -2.0) sharpness = -2.0;	
	sprintf(filter_descr, "unsharp=5:5:%.1f", sharpness);

    if(picture_edit_init(&edit_ctx, sourcePath, filter_descr))
	{
		printf("picture_edit_init failed \n");
		return NULL;
	}

	picture_codec_process(&edit_ctx.ffmpeg_context);

	// write_file(edit_ctx.data, edit_ctx.length);

    picture_edit_exit(&edit_ctx);
	return NULL;
}



